package com.hzw.saas.common.flow.service.impl;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.annotation.Resource;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzw.saas.api.user.IUserAccountService;
import com.hzw.saas.api.user.bo.UserAccountBO;
import com.hzw.saas.common.flow.mapper.FlowProcessRecordMapper;
import com.hzw.saas.common.flow.pojo.bo.FlowProcessRecordBO;
import com.hzw.saas.common.flow.pojo.model.FlowNode;
import com.hzw.saas.common.flow.pojo.model.FlowProcess;
import com.hzw.saas.common.flow.pojo.model.FlowProcessRecord;
import com.hzw.saas.common.flow.service.IFlowNodeService;
import com.hzw.saas.common.flow.service.IFlowProcessRecordService;
import com.hzw.saas.common.flow.service.IFlowProcessService;
import com.hzw.saas.common.util.MapperUtil;
import cn.hutool.core.collection.CollUtil;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author sonam
 * @since 2021-08-04
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FlowProcessRecordServiceImpl extends ServiceImpl<FlowProcessRecordMapper, FlowProcessRecord> implements IFlowProcessRecordService {

    @Resource
    private IUserAccountService userAccountService;
    @Resource
    private IFlowNodeService flowNodeService;
    @Resource
    private IFlowProcessService flowProcessService;

    @Override
    public boolean save(FlowProcessRecord flowProcessRecord) {
        if (flowProcessRecord.getStep() == null) {
            Integer newStep = this.baseMapper.getNewStep(flowProcessRecord.getFlowInstanceId());
            flowProcessRecord.setStep(Objects.isNull(newStep) ? 1 : newStep + 1);
        }
        return super.save(flowProcessRecord);
    }

    @Override
    public FlowProcessRecordBO getLatestPushOnRecord(String flowInstanceId) {
        FlowProcessRecord processRecord = super.baseMapper.getLatestPushOnProcess(flowInstanceId);
        return MapperUtil.nf().map(processRecord, FlowProcessRecordBO.class);
    }

    @Override
    public List<FlowProcessRecordBO> listRecordBOs(String flowInstanceId) {
        // 查询所有的用户审批记录
        List<FlowProcessRecord> records = super.lambdaQuery().
            eq(FlowProcessRecord::getFlowInstanceId, flowInstanceId)
            .orderByAsc(FlowProcessRecord::getStep).list();
        if (CollUtil.isEmpty(records)) {
            return new ArrayList<>();
        }
        // pid, flowInstanceId, flowProcessId, step, approver, suggestion, createTime
        List<FlowProcessRecordBO> result = MapperUtil.nf().mapAsList(records, FlowProcessRecordBO.class);

        // batch get approver
        List<String> userIds = records.stream().map(FlowProcessRecord::getApprover).collect(Collectors.toList());
        List<UserAccountBO> userAccounts = userAccountService.listAccounts(userIds);
        Map<String, UserAccountBO> userMap = userAccounts.stream().collect(Collectors.toMap(UserAccountBO::getUserId, u -> u, (k1, k2) -> k1));

        // batch get flowProcess
        List<String> flowProcessIds = records.stream().map(FlowProcessRecord::getFlowProcessId).collect(Collectors.toList());
        List<FlowProcess> flowProcesses = flowProcessService.listByIds(flowProcessIds);
        Map<String, FlowProcess> flowProcessMap = flowProcesses.stream().collect(Collectors.toMap(FlowProcess::getPid, f -> f, (k1, k2) -> k1));

        // batch get flowNodes
        List<String> flowNodeIds = flowProcesses.stream().flatMap(f -> Stream.of(f.getFlowNodePreId(), f.getFlowNodeNextId())).distinct().collect(Collectors.toList());
        List<FlowNode> flowNodes = flowNodeService.listByIds(flowNodeIds);
        Map<String, FlowNode> flowNodeMap = flowNodes.stream().collect(Collectors.toMap(FlowNode::getPid, f -> f, (k1, k2) -> k1));

        // 过滤
        Iterator<FlowProcessRecordBO> iterator = result.iterator();
        while (iterator.hasNext()) {
            FlowProcessRecordBO recordBO = iterator.next();
            // 过滤flowProcess前后节点一样的数据
            FlowProcess flowProcess = flowProcessMap.get(recordBO.getFlowProcessId());
            if (flowProcess == null || Objects.equals(flowProcess.getFlowNodePreId(), flowProcess.getFlowNodeNextId())) {
                iterator.remove();
                continue;
            }
            recordBO.setFlowProcessName(flowProcess.getFlowProcessName());
            recordBO.setFlowProcessTitle(flowProcess.getFlowProcessTitle());
            recordBO.setFlowProcessTip(flowProcess.getFlowProcessTip());
            recordBO.setFlowProcessStyle(flowProcess.getFlowProcessStyle());
            // curFlowNodeName
            Optional<FlowNode> curFlowNodeOptional = Optional.ofNullable(flowNodeMap.get(flowProcess.getFlowNodePreId()));
            recordBO.setCurFlowNodeName(curFlowNodeOptional.map(FlowNode::getFlowNodeName).orElse(""));
            // tarFlowNodeName
            Optional<FlowNode> tarFlowNodeOptional = Optional.ofNullable(flowNodeMap.get(flowProcess.getFlowNodeNextId()));
            recordBO.setTarFlowNodeName(tarFlowNodeOptional.map(FlowNode::getFlowNodeName).orElse(""));
            // approverName
            Optional<UserAccountBO> accountOptional = Optional.ofNullable(userMap.get(recordBO.getApprover()));
            recordBO.setApproverName(accountOptional.map(UserAccountBO::getUserName).orElse(""));

        }
        return result;
    }
}
